"""
This file is part of open-hea.

open-hea is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.

open-hea is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with open-hea.  If not, see <http://www.gnu.org/licenses/>.
"""


__author__ = 'Colin Newell <colin.newell@gmail.com>'
__date__ = 'September 2012'
__credits__ = ''

import ConfigParser
import os


class OpenHEAConfig(ConfigParser.SafeConfigParser):

    """
    Configuration file parser based on
    ConfigParser.SafeConfigParser

    The parser is setup with defaults for most of the
    settings.

        config = OpenHEAConfig()
        config.read(CONFIGFILE)

    The config file can contain these directives,

        [database]
        host = host
        database = database
        user = user
        password = userpassword
        port = 3306
        superuser = root
        superuser_password = password
        driver = mysql+mysqldb

    """

    def __init__(self):
        self.defaults = {
            'host': 'localhost',
            'database': 'openheadb',
            'user': 'openhea',
            'password': 'hea2012',
            'port': '3306',
            'superuser': 'root',
            'superuser_password': '',
        }
        ConfigParser.SafeConfigParser.__init__(self, self.defaults,
                                                allow_no_value=True)
        self.defaults['port'] = int(self.defaults['port'])

    def database_config(self):
        """
        Returns a dictionary containing the database configuration
        information.  If it can not load the settings from the
        ini file it simply returns the default settings.

            {
                'host': 'localhost',
                'database': 'openheadb',
                'user': 'openhea',
                'password': 'hea2012',
                'port': 3306,
                'superuser': 'root',
                'superuser_password': '',
            }
        """
        # FIXME: should we also be returning utf8 and warnings params
        # here?
        try:
            return {
                'host':               self.get('database', 'host'),
                'database':           self.get('database', 'database'),
                'user':               self.get('database', 'user'),
                'password':           self.get('database', 'password'),
                'port':               self.getint('database', 'port'),
                'superuser':          self.get('database', 'superuser'),
                'superuser_password': self.get('database',
                                                  'superuser_password'),
            }
        except ConfigParser.NoOptionError:
            return self.defaults.copy()
        except ConfigParser.NoSectionError:
            return self.defaults.copy()

    def dbinfo(self):
        """
        Returns a dictionary containing the database configuration
        information.

            {
                'host': 'localhost',
                'database': 'openheadb',
                'user': 'openhea',
                'password': 'hea2012',
                'charset': 'utf8',
                'use_unicode'   : True,
                'get_warnings'  : True,
            }
        """
        config = self.database_config()
        # this makes the config consistent with what is currently returned.
        for key in ['superuser_password', 'superuser', 'port']:
            del config[key]
        config['charset'] = 'utf8'
        for key in ['use_unicode', 'get_warnings']:
            config[key] = True
        socket = self.sqlalchemy_mysql_unix_socket()
        if socket:
            config['unix_socket'] = socket
        return config

    def superuser_dbinfo(self):
        """
        Returns a dictionary containing the database configuration
        information for the super user.

            {
                'host': 'localhost',
                'database': 'openheadb',
                'user': 'root',
                'password': '',
                'charset': 'utf8',
                'use_unicode'   : True,
                'get_warnings'  : True,
            }
        """
        config = self.database_config()
        # this makes the config consistent with what is currently returned.
        config['user'] = config['superuser']
        config['password'] = config['superuser_password']
        for key in ['superuser_password', 'superuser', 'port']:
            del config[key]
        config['charset'] = 'utf8'
        for key in ['use_unicode', 'get_warnings']:
            config[key] = True
        socket = self.sqlalchemy_mysql_unix_socket()
        if socket:
            config['unix_socket'] = socket
        return config

    def get_driver(self):
        """
        Returns the database driver to use in sqlalchemy
        """
        try:
            return self.get('database', 'driver')
        except ConfigParser.NoOptionError:
            pass
        except ConfigParser.NoSectionError:
            pass
        return 'mysql+mysqldb'

    def schema_script_path(self):
        """
        Returns the path to look for the database schema
        scripts.  This is primarily configurable to make
        testing easier.
        """
        try:
            return self.get('database', 'schema_script_path')
        except ConfigParser.NoOptionError:
            pass
        except ConfigParser.NoSectionError:
            pass
        return os.path.join(os.path.dirname(__file__), 'scripts')

    def sqlalchemy_mysql_unix_socket(self):
        """
        Returns the unix socket specified in the configuration file
        for the sqlalchemy connection.

        This shouldn't be a commonly necessary function, but it is
        used on our CI server.  The parameter should be unix_socket
        in the configuration file.  For example,

            unix_socket = /var/run/mysqld/mysqld.sock
        """
        try:
            return self.get('database', 'unix_socket')
        except ConfigParser.NoOptionError:
            pass
        except ConfigParser.NoSectionError:
            pass
        return None

    def sqlalchemy_connection_string(self):
        """
        Returns a connection string for sqlalchemy.  The defaults will produce
        the following connection string,

            mysql+mysqldb://openhea:hea2012@localhost/openheadb

        """
        config = self.database_config()
        return self._create_sqlalchemy_connection_string(config['user'],
                                    config['password'], config['host'],
                                    config['database'])

    def sqlalchemy_superuser_connection_string(self):
        """
        Returns a connection string for the superuser for sqlalchemy.
        The defaults will produce the following connection string,

        Note: this may not work with blank passwords.  Then again it
        might.  I have no way to test it, your mileage may vary.
        """
        config = self.database_config()
        return self._create_sqlalchemy_connection_string(config['superuser'],
                                    config['superuser_password'],
                                    config['host'], config['database'])

    def _create_sqlalchemy_connection_string(self, user, password,
                                            host, database):
        driver = self.get_driver()
        socket = self.sqlalchemy_mysql_unix_socket()
        config_string = "%s://%s:%s@%s/%s" % (driver, user,
                                    password, host, database)
        if socket:
            config_string = "%s?unix_socket=%s" % (config_string, socket)
        return config_string
